package com.ymsoft.myerp.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ymsoft.myerp.common.DTO;
import com.ymsoft.myerp.common.RetEnum;
import com.ymsoft.myerp.entity.Role;
import com.ymsoft.myerp.entity.TokenCarrier;
import com.ymsoft.myerp.entity.User;
import com.ymsoft.myerp.entity.UserDetail;
import com.ymsoft.myerp.exception.CustomException;
import com.ymsoft.myerp.service.ILoginService;
import com.ymsoft.myerp.service.IRoleService;
import com.ymsoft.myerp.service.IUserService;
import com.ymsoft.myerp.util.JwtUtils;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Date;

/**
 * @author: yzr
 * @date: 2020/4/12
 */
@Service
public class LoginServiceImpl implements ILoginService {

    private final AuthenticationManager authenticationManager;

    @Autowired
    @Qualifier("MyUserDetailService")
    private UserDetailsService userDetailsService;

    @Autowired
    private IUserService iUserService;

    @Autowired
    private IRoleService iRoleService;

    @Autowired
    private JwtUtils jwtUtils;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Autowired
    public LoginServiceImpl(@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    /**
     * 注册用户
     *
     * @param userDetail
     * @return
     */
    @Override
    public UserDetail register(UserDetail userDetail) {
        final String username = userDetail.getUsername();
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("username", username);
        User user = iUserService.getOne(userQueryWrapper, false);
        if (null != user) {
            throw new CustomException(DTO.ret(RetEnum.BAD_REQUEST, "用户已存在"));
        }
        user = new User();
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        final String rawPassword = userDetail.getPassword();
        userDetail.setPassword(encoder.encode(rawPassword));
        userDetail.setCreatedDate(LocalDateTime.now());
        user.setUsername(username);
        user.setPassword(encoder.encode(rawPassword));
        iUserService.save(user);
        long roleId = userDetail.getRole().getId();
        Role role = iRoleService.getById(roleId);
        userDetail.setRole(role);
        // 插入关联关系表
//        authMapper.insertRole(userDetail.getId(), roleId);
        return userDetail;
    }

    /**
     * 登陆
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public TokenCarrier login(String username, String password) {
        //用户验证
        final Authentication authentication = authenticate(username, password);
        //存储认证信息
        SecurityContextHolder.getContext().setAuthentication(authentication);
        //生成token
        final UserDetail userDetail = (UserDetail) authentication.getPrincipal();
        final String token = jwtUtils.generateAccessToken(userDetail);
        //存储token
        jwtUtils.putToken(username, token);
        return new TokenCarrier(token, userDetail);
    }

    /**
     * 登出
     *
     * @param token
     */
    @Override
    public void logout(String token) {
        token = token.substring(tokenHead.length());
        String userName = jwtUtils.getUsernameFromToken(token);
        jwtUtils.deleteToken(userName);
    }

    /**
     * 刷新Token
     *
     * @param oldToken
     * @return
     */
    @Override
    public TokenCarrier refresh(String oldToken) {
        String token = oldToken.substring(tokenHead.length());
        String username = jwtUtils.getUsernameFromToken(token);
        UserDetail userDetail = (UserDetail) userDetailsService.loadUserByUsername(username);
        if (jwtUtils.canTokenBeRefreshed(token, userDetail.getCreatedDate())) {
            token = jwtUtils.refreshToken(token);
            return new TokenCarrier(token, userDetail);
        }
        return null;
    }

    /**
     * 根据Token获取用户信息
     *
     * @param token
     * @return
     */
    @Override
    public UserDetail getUserByToken(String token) {
        token = token.substring(tokenHead.length());
        return jwtUtils.getUserFromToken(token);
    }

    private Authentication authenticate(String username, String password) {
        try {
            //该方法会去调用userDetailsService.loadUserByUsername()去验证用户名和密码，如果正确，则存储该用户名密码到“security 的 context中”
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (DisabledException | BadCredentialsException e) {
            throw new CustomException(DTO.ret(RetEnum.LOGIN_ERROR, e.getMessage()));
        }
    }
}
